﻿#region Copyright(C) 2010-2010 NCS Pte. Ltd. All rights reserved.
// ==================================================================================================
// Copyright(C) 2010 NCS Pte. Ltd. All rights reserved.
//
// SYSTEM NAME	    : iConnect .Net Application Framework
// COMPONENT ID	    : CBEC.Core.Wcf
// COMPONENT DESC   : Core components for WCF.	
//
// CREATED DATE/BY  : 18 Aug 2010 / Gao Ye
//
// REVISION HISTORY :	
// DATE/BY			SR#/CS/PM#/OTHERS		DESCRIPTION OF CHANGE
// ==================================================================================================
#endregion

using CBEC.Core;
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;

namespace NCS.IConnect.ExceptionHandling.Wcf
{
    /// <summary>
    /// The extended <see cref="ChannelFactory&lt;TChannel&gt;"/>
    /// </summary>
    /// <typeparam name="TChannel">The type of the channel.</typeparam>
    public class ExceptionHandlingChannelFactory<TChannel>:ChannelFactory<TChannel>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ExceptionHandlingChannelFactory&lt;TChannel&gt;"/> class.
        /// </summary>
        /// <param name="binding">The binding.</param>
        public ExceptionHandlingChannelFactory(Binding binding):base(binding)
        {}

        /// <summary>
        /// Initializes a new instance of the <see cref="ExceptionHandlingChannelFactory&lt;TChannel&gt;"/> class.
        /// </summary>
        /// <param name="endpoint">The <see cref="T:System.ServiceModel.Description.ServiceEndpoint"/> for the channels produced by the factory.</param>
        /// <exception cref="T:System.ArgumentNullException">The <paramref name="endpoint"/> is null.</exception>
        public ExceptionHandlingChannelFactory(ServiceEndpoint endpoint):base(endpoint)
        {}

        /// <summary>
        /// Initializes a new instance of the <see cref="ExceptionHandlingChannelFactory&lt;TChannel&gt;"/> class.
        /// </summary>
        /// <param name="channelType">Type of the channel.</param>
        protected ExceptionHandlingChannelFactory(Type channelType):base(channelType)
        {}
        /// <summary>
        /// Initializes a new instance of the <see cref="ExceptionHandlingChannelFactory&lt;TChannel&gt;"/> class.
        /// </summary>
        /// <param name="endpointConfigurationName">Name of the endpoint configuration.</param>
        public ExceptionHandlingChannelFactory(string endpointConfigurationName)
            : base(endpointConfigurationName)
        { }

        /// <summary>
        /// Initializes a new instance of the <see cref="ExceptionHandlingChannelFactory&lt;TChannel&gt;"/> class.
        /// </summary>
        /// <param name="binding">The binding.</param>
        /// <param name="remoteAddress">The remote address.</param>
        public ExceptionHandlingChannelFactory(Binding binding, EndpointAddress remoteAddress):base(binding,remoteAddress)
        {}

        /// <summary>
        /// Initializes a new instance of the <see cref="ExceptionHandlingChannelFactory&lt;TChannel&gt;"/> class.
        /// </summary>
        /// <param name="binding">The binding.</param>
        /// <param name="remoteAddress">The remote address.</param>
        public ExceptionHandlingChannelFactory(Binding binding, string remoteAddress):base(binding,remoteAddress)
        {}

        /// <summary>
        /// Initializes a new instance of the <see cref="ExceptionHandlingChannelFactory&lt;TChannel&gt;"/> class.
        /// </summary>
        /// <param name="endpointConfigurationName">Name of the endpoint configuration.</param>
        /// <param name="remoteAddress">The remote address.</param>
        public ExceptionHandlingChannelFactory(string endpointConfigurationName, EndpointAddress remoteAddress):base(endpointConfigurationName,remoteAddress)
        {}

        /// <summary>
        /// Creates a description of the service endpoint.
        /// </summary>
        /// <returns>
        /// The <see cref="T:System.ServiceModel.Description.ServiceEndpoint"/> of the service.
        /// </returns>
        /// <exception cref="T:System.InvalidOperationException">The callback contract is null but the service endpoint requires one that is non-null.</exception>
        protected override ServiceEndpoint CreateDescription()
        {
            ServiceEndpoint endpoint = base.CreateDescription();
            foreach (OperationDescription operation in endpoint.Contract.Operations)
            {
                if (!FaultDescriptionExists(operation, typeof(ServiceExceptionDetail)))
                {
                    string action = ServiceExceptionDetail.GetFaultAction(endpoint.Contract.Namespace, operation.Name);
                    FaultDescription faultDescription = new FaultDescription(action);
                    faultDescription.DetailType = typeof(ServiceExceptionDetail);
                    operation.Faults.Add(faultDescription);
                }

                if (!FaultDescriptionExists(operation, typeof(ValidationFault)))
                {
                    string action = ValidationFault.GetFaultAction(endpoint.Contract.Namespace, operation.Name);
                    FaultDescription faultDescription = new FaultDescription(action);
                    faultDescription.DetailType = typeof(ValidationFault);
                    operation.Faults.Add(faultDescription);
                }
            }

            return endpoint;
        }

        
        private static bool FaultDescriptionExists(OperationDescription operation, Type faultType)
        {
            foreach (var fault in operation.Faults)
            {
                if (fault.DetailType == faultType)
                {
                    return true;
                }
            }

            return false;
        }
    }
}